package com.sugon.modules.device.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.sugon.dao.DevMaintenanceTicketDao;
import com.sugon.entity.DevMaintenancePlanChangeEntity;
import com.sugon.entity.DevMaintenanceTicketEntity;
import com.sugon.entity.DevMaintenanceTicketItemEntity;
import com.sugon.modules.base.model.vo.ProcessProgressConst;
import com.sugon.modules.device.consts.DevMaintenanceItemExecuteStatus;
import com.sugon.modules.device.consts.DevMaintenanceTicketStatus;
import com.sugon.modules.device.model.dto.DevAmTicketLineStatDTO;
import com.sugon.modules.device.model.dto.DevAmTicketStatDTO;
import com.sugon.modules.device.model.dto.DevAmTicketWorkshopStatDTO;
import com.sugon.modules.device.model.vo.DelayCheckParam;
import com.sugon.modules.device.model.vo.DevMaintenanceDelayApplyParam;
import com.sugon.modules.device.model.vo.DevMaintenanceTicketVO;
import com.sugon.modules.device.service.IDeviceMaintenanceTicketManager;
import com.sugon.service.DevMaintenancePlanChangeService;
import com.sugon.service.DevMaintenanceTicketService;
import com.sugon.service.DevReportUrgeService;
import com.sugon.service.SysMsgService;
import com.sugon.utils.ProcessInfoEnum;
import com.sugon.utils.ShiroUtils;
import org.apache.shiro.util.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author ： YuXD
 * @description： 设备维护工单Manager实现类
 * @date ： 2020-11-18 下午 5:04
 * @version: 1.0
 */
@Service
public class DeviceMaintenanceTicketManagerImpl implements IDeviceMaintenanceTicketManager {

    @Autowired
    private DevMaintenancePlanChangeService devMaintenancePlanChangeService;
    @Autowired
    private DevMaintenanceTicketService devMaintenanceTicketService;
    @Autowired
    private SysMsgService sysMsgService;
    @Autowired
    private DevReportUrgeService devReportUrgeService;
    @Autowired
    private DevMaintenanceTicketDao devMaintenanceTicketDao;

    /**
     * 催办
     *
     * @param ticketId 工单ID
     * @param userId   催办人ID
     * @return
     */
    @Override
    public synchronized boolean urge(String ticketId, String userId) {
        DevMaintenanceTicketEntity ticket = devMaintenanceTicketService.queryObject(ticketId);
        Assert.notNull(ticket, "维修工单不存在，工单ID: " + ticketId);
        // 1、更新维修工单状态
        ticket.setIsUrged(1);
        boolean flag = devMaintenanceTicketService.update(ticket) > 0;
        if (flag) {
            // 2、保存催办记录
            devReportUrgeService.save(ticketId, "MAINTENANCE");
            // 3、更新工单消息提醒
            sysMsgService.addRemindItem(ProcessInfoEnum.DEV_ZXGD, ticketId, ticket.getExecutor());
        }
        return flag;
    }

    /**
     * 申请变更
     *
     * @param ticketChangeApplyParam
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean applyChange(DevMaintenanceDelayApplyParam ticketChangeApplyParam) {
        DevMaintenanceTicketEntity ticket = ticketChangeApplyParam.getDevMaintenanceTicket();
        // 1、生成工单申请记录，并保存
        DevMaintenancePlanChangeEntity changeRecord = new DevMaintenancePlanChangeEntity();
        CopyOptions copyOptions = CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true);
        BeanUtil.copyProperties(ticketChangeApplyParam, changeRecord, copyOptions);
        changeRecord.setOriginalTime(ticket.getFinalEndTime());
        changeRecord.setApplier(ticketChangeApplyParam.getApplier());
        changeRecord.setProgress(ProcessProgressConst.DEPT_APPROVING);
        boolean flag = devMaintenancePlanChangeService.save(changeRecord) > 0;
        if (flag) {
            // 2、更改维修工单状态
            ticket.setStatus(DevMaintenanceTicketStatus.DELAY_APPLYING);
            devMaintenanceTicketService.update(ticket);
            // 3、生成审核信息和启动流程
            sysMsgService.addDevMaintenancePlanChangeApproveItem(ticket.getId(), 0);
        }
        return flag;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean checkChange(DelayCheckParam delayCheckParam) {
        DevMaintenancePlanChangeEntity applyRecord = delayCheckParam.getApplyRecord();
        cn.hutool.core.lang.Assert.notNull(applyRecord);
        applyRecord.setChecker(ShiroUtils.getUserId());
        applyRecord.setProgress(delayCheckParam.getApprovalStatus());
        boolean flag = devMaintenancePlanChangeService.update(applyRecord) > 0;
        if (flag) {
            DevMaintenanceTicketEntity ticket = delayCheckParam.getTicket();
            cn.hutool.core.lang.Assert.notNull(applyRecord);
            ticket.setStatus(DevMaintenanceTicketStatus.DELAY_MAINTAINING);
            ticket.setFinalEndTime(applyRecord.getChangeTime());
            devMaintenanceTicketService.update(ticket);
        }
        return flag;
    }

    @Override
    public Map<String, Object> prepareExportData(Map<String, Object> params) {
        // 如果查询的执行时间不为空，那么回填年度和周次
        String executeTimeStr = MapUtil.getStr(params, "executeTime");
        cn.hutool.core.lang.Assert.isTrue(StrUtil.isNotEmpty(executeTimeStr));
        Date executeTime = DateUtil.parseDate(executeTimeStr);
        int yearly = DateUtil.year(executeTime);
        int weekOfYear = DateUtil.weekOfYear(executeTime);

        // 查看工单结束日期所在的周次查询
        Date executeEndTime = MapUtil.getDate(params, "executeEndTime");
        if (executeEndTime != null) {
            params.put("startTime", DateUtil.formatDateTime(DateUtil.beginOfWeek(executeEndTime)));
            params.put("endTime", DateUtil.formatDateTime(DateUtil.endOfWeek(executeEndTime)));
            params.remove("executeEndTime");
        }
        // 获取工单状态
        List<String> statusList = null;
        String status = MapUtil.getStr(params, "status");
        if (StrUtil.isNotEmpty(status)) {
            statusList = StrUtil.split(status, ",");
        }
        // 构建PM工单统计信息
        DateTime beginOfWeek = DateUtil.beginOfWeek(executeTime);
        Date endOfWeek = DateUtil.endOfWeek(executeTime);
        DevAmTicketStatDTO statResult = new DevAmTicketStatDTO(yearly, weekOfYear, DateUtil.formatDate(beginOfWeek), DateUtil.formatDate(endOfWeek));
        List<DevMaintenanceTicketVO> pmTicketList = devMaintenanceTicketDao.queryMatched(statusList, MapUtil.getStr(params, "deptCode"), MapUtil.getStr(params, "ticketType"), yearly, weekOfYear, DateUtil.formatDateTime(beginOfWeek), DateUtil.formatDateTime(endOfWeek));
        List<DevAmTicketWorkshopStatDTO> workshopStats = CollectionUtil.newArrayList();
        if (CollectionUtil.isNotEmpty(pmTicketList)) {
            Map<String, List<DevMaintenanceTicketVO>> workshopTicketGroups = pmTicketList.stream().filter(ticket -> StrUtil.isNotEmpty(ticket.getWorkshopName())).collect(Collectors.groupingBy(DevMaintenanceTicketVO::getWorkshopName));
            workshopTicketGroups.forEach((workshopName, workshopTicketList) -> {
                DevAmTicketWorkshopStatDTO workshopStat = new DevAmTicketWorkshopStatDTO(workshopName);
                List<DevAmTicketLineStatDTO> lineStats = CollectionUtil.newArrayList();
                Map<String, List<DevMaintenanceTicketVO>> lineTicketGroups = workshopTicketList.stream().collect(Collectors.groupingBy(DevMaintenanceTicketVO::getProductLineName));
                lineTicketGroups.forEach((lineName, lineTicketList) -> {
                    // 过滤下，只保留有效记录
                    lineTicketList = lineTicketList.stream().filter(lineTicket -> StrUtil.isNotEmpty(lineTicket.getRepairCode())).collect(Collectors.toList());

                    DevAmTicketLineStatDTO lineStat = new DevAmTicketLineStatDTO(lineName, lineTicketList.size());
                    // 超期工单数：只要是未完成的都算作是超期工单数
                    lineStat.setOvertimeNum(lineTicketList.stream().filter(ticket -> !DevMaintenanceTicketStatus.COMPLETE.equals(ticket.getStatus())).count());
                    // 维护项目数
                    List<DevMaintenanceTicketItemEntity> lineAmTicketItemList = CollectionUtil.newArrayList();
                    for (DevMaintenanceTicketEntity amTicket : lineTicketList) {
                        lineAmTicketItemList.addAll(amTicket.getAmItems());
                    }
                    lineStat.setAmItemNum(lineAmTicketItemList.size());
                    if (CollectionUtil.isNotEmpty(lineAmTicketItemList)) {
                        long minAmItemOvertimeNum = 10080;
                        long maxAmItemOvertimeNum = 0;
                        // 已完成维护项数
                        long amItemEdNum = 0;
                        // 延期完成数
                        long amItemDelayEdNum = 0;
                        // 未执行维护项数
                        long amItemUnNum = 0;
                        long overtimeSumNum = 0L;
                        String maxOvertimeAmTicketCode = "";
                        for (DevMaintenanceTicketItemEntity lineAmTicketItem : lineAmTicketItemList) {
                            Date implementDate = lineAmTicketItem.getImplementDate();
                            if (implementDate == null) {
                                amItemUnNum += 1;
                                continue;
                            } else {
                                if (NumberUtil.equals(DevMaintenanceItemExecuteStatus.DELAY_ED, lineAmTicketItem.getStatus())) {
                                    amItemDelayEdNum += 1;
                                    // 超时时间长
                                    long overtimeDuration = DateUtil.between(endOfWeek, implementDate, DateUnit.MINUTE);
                                    // 设置最大超时数
                                    if (overtimeDuration > maxAmItemOvertimeNum) {
                                        maxAmItemOvertimeNum = overtimeDuration;
                                        maxOvertimeAmTicketCode = lineAmTicketItem.getRepairCode();
                                    }
                                    // 设置最小超时数
                                    if (overtimeDuration < minAmItemOvertimeNum) {
                                        minAmItemOvertimeNum = overtimeDuration;
                                    }
                                    // 超时和累加
                                    overtimeSumNum += overtimeDuration;
                                } else {
                                    amItemEdNum += 1;
                                }
                            }
                        }
                        lineStat.setAmItemOvertimeNum(amItemDelayEdNum);
                        lineStat.setAmItemEdNum(amItemEdNum);
                        lineStat.setAmItemUnNum(amItemUnNum);

                        // 延期完成项目超期时长（最小值）分钟
                        lineStat.setMinAmItemOvertimeNum(minAmItemOvertimeNum < 10080 ? minAmItemOvertimeNum : null);
                        // 延期完成项目超期时长（最大值）分钟
                        lineStat.setMaxAmItemOvertimeNum(maxAmItemOvertimeNum > 0 ? maxAmItemOvertimeNum : null);
                        // 延期完成项目超期时长（平均值）分钟
                        lineStat.setAvgAmItemOvertimeNum(amItemDelayEdNum > 0 ? overtimeSumNum / amItemDelayEdNum : null);
                        // 延期完成工单号（最长超期）
                        lineStat.setMaxOvertimeAmTicketCode(maxOvertimeAmTicketCode);
                    }
                    lineStats.add(lineStat);
                });
                workshopStat.setLineStats(lineStats);
                workshopStats.add(workshopStat);
            });
        }
        statResult.setWorkshopStats(workshopStats);
        return BeanUtil.beanToMap(statResult);
    }
}
